Skip to content

feat(launcher): compact icon+name tiles in the 9-dots app menu - #268

Merged
izzywdev merged 6 commits into
masterfrom
claude/9dots-menu-icon-name-68pjzm
Jul 21, 2026
Merged

feat(launcher): compact icon+name tiles in the 9-dots app menu#268
izzywdev merged 6 commits into
masterfrom
claude/9dots-menu-icon-name-68pjzm

Conversation

@izzywdev

Copy link
Copy Markdown
Owner

📋 Description

The 9-dots top-bar launcher (AppSelector) reused the full-detail design-system AppCard — icon, name, integration badge, health state and description — turning the popup into a dense wall of text. This reworks it to look like the Google app launcher: each app is now just its icon and name.

🔄 Type of Change

  • ✨ New feature (non-breaking change which adds functionality)
  • 🔧 Refactoring (no functional changes)

🧪 Testing

  • Type resolution verified (@fuzefront/design-system → regenerated index.d.ts now exports AppTile; frontend type-check shows only a pre-existing unrelated baseUrl deprecation)
  • Existing launcher e2e assertions reviewed for compatibility

Runtime console-clean gate (ui-runtime-validation) not run: the Chrome DevTools MCP plugin is user/environment-scoped and is not installed in this cloud session, so the mandated real-Chromium render/console check could not be executed here. It should be run before merge.

Test Instructions

npm install
npm run test
npm run build

🔧 Implementation Details

Changes Made

  • Frontend Changes:
    • frontend/src/components/AppSelector.tsx: swap AppCardAppTile, drop the per-app description, widen the grid from 2 to 3 columns. The .app-grid-button hook and the per-app name text are unchanged, so the existing launcher e2e assertions (clock-load.spec.ts, federated-apps-register-activate.frontend.spec.ts) still match.
  • Design System Changes:
    • New design-system/components/launcher/AppTile.{jsx,d.ts,prompt.md} — a compact icon+name cell reusing the existing HealthDot primitive. Offline apps stay grayscaled/dimmed/inert with a corner health dot. Tokens-only, no raw hex/px/type.
    • Regenerated the DS barrels + manifest via build.mjs (index.js, index.d.ts, _ds_manifest.json).
    • AppCard is left untouched — the dashboard / Applications management surfaces legitimately need the full-detail card.

Code Quality

  • Code follows the project's coding standards (design-system-first, tokens-only)
  • Self-review of code completed
  • No console.log or debugging statements left in code

🚨 Breaking Changes

None. AppTile is additive; AppCard and its consumers are unchanged.

📊 Performance Impact

Bundle Size Impact: No significant impact (one small component added; the launcher renders fewer nodes per app).

🔄 Backwards Compatibility

  • Fully backwards compatible

📝 Additional Notes

The launcher popup keeps its existing width/positioning math (dropdownWidth = 360); only the inner grid layout and per-app cell changed.

🤖 Generated with Claude Code

https://claude.ai/code/session_016PMVXVQ5XUh8ZfFx8Vr7XW


Generated by Claude Code

The 9-dots top-bar launcher reused the full-detail <AppCard> (icon, name,
integration badge, health, description), making it a dense wall of text.
Model it on the Google app launcher instead: a new <AppTile> DS primitive
renders only the app icon and its menu label in a 3-column grid.

- Add design-system/components/launcher/AppTile.{jsx,d.ts,prompt.md} — a
  compact icon+name cell reusing the HealthDot primitive; offline apps stay
  grayscaled/dimmed/inert. <AppCard> remains for the dashboard/management
  surfaces that legitimately need full detail.
- Regenerate the DS barrels + manifest (build.mjs).
- AppSelector: swap AppCard -> AppTile, drop the description, widen the grid
  to 3 columns. The .app-grid-button hook and per-app name text are
  unchanged, so the existing launcher e2e assertions still match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016PMVXVQ5XUh8ZfFx8Vr7XW
@github-actions
github-actions Bot enabled auto-merge (squash) July 15, 2026 14:53
@github-actions

Copy link
Copy Markdown
Contributor

Automated code review (gate-code-review)

design-system/components/launcher/AppTile.jsx:96 — When iconUrl is present but the image fails to load, onError only sets display:none on the <img>; it does not swap in the emoji fallback. The fallback glyph <div> is rendered only in the !iconUrl branch, so a broken icon URL leaves a blank space instead of the per-type emoji. This contradicts the documented contract ("falls back to a per-type emoji glyph on error or when absent").

Report-only — this check never blocks merge.

The onError handler only hid the broken <img>, leaving a blank space and
contradicting the documented contract ("falls back to a per-type emoji glyph
on error or when absent"). Track the load failure in state and render the
emoji fallback node instead of just hiding the image.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016PMVXVQ5XUh8ZfFx8Vr7XW
@github-actions

Copy link
Copy Markdown
Contributor

CI Fix — lock file regenerated

Root cause: npm ci in the Playwright sign-in flow job failed because package-lock.json was out of sync with package.json:

npm error Missing: @fuzefront/security-client@0.1.0 from lock file
npm error Missing: @types/node@18.19.0 from lock file
npm error Missing: openapi-typescript@7.13.0 from lock file
npm error Missing: typescript@5.1.6 from lock file

The packages/security workspace (@fuzefront/security-client@0.1.0) is declared in package.json workspaces but was never added to package-lock.json. npm ci is strict and refuses to install when the lock file doesn't match.

Fix: Ran npm install to regenerate package-lock.json, adding the missing workspace and its dev-dependencies.

Branch with fix: claude-auto-fix-ci-claude/9dots-menu-icon-name-68pjzm-29425687822 (commit 61b6bac)

The fix branch is ready — once merged into claude/9dots-menu-icon-name-68pjzm, CI should pass.

master's lockfile drifted: the packages/security workspace
(@fuzefront/security-client@0.1.0) and its dev-deps (@types/node@18.19.0,
openapi-typescript@7.13.0, typescript@5.1.6) were declared in package.json
but never added to package-lock.json (introduced by #260), so `npm ci`
failed strictly on every PR. Regenerated the lock (npm install
--package-lock-only) to add only the missing workspace + dev-deps; no other
dependency versions change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016PMVXVQ5XUh8ZfFx8Vr7XW
@github-actions

Copy link
Copy Markdown
Contributor

CI Fix: Lock file regenerated for packages/security workspace

Root cause: The packages/security workspace (@fuzefront/security-client@0.1.0) was added to the repo in a prior commit but npm install was never run afterward. This left the root package-lock.json missing entries for:

  • @fuzefront/security-client@0.1.0
  • @types/node@18.19.0
  • openapi-typescript@7.13.0
  • typescript@5.1.6

Every CI job running npm ci at the root failed with Missing: @fuzefront/security-client@0.1.0 from lock file.

Fix: Ran npm install --package-lock-only on branch claude-auto-fix-ci-claude/9dots-menu-icon-name-68pjzm-29425677546 to regenerate the lock file. npm ci --dry-run now exits 0.

The fix branch has been pushed. A PR from it targeting claude/9dots-menu-icon-name-68pjzm could not be created automatically (GitHub Actions cannot create PRs in this repo), but the commit is at b7d48d9 on origin/claude-auto-fix-ci-claude/9dots-menu-icon-name-68pjzm-29425677546.

@github-actions

Copy link
Copy Markdown
Contributor

CI Fix — lock file sync

Branch with fix: `claude-auto-fix-ci-claude/9dots-menu-icon-name-68pjzm-29425846456`

Root cause

The packages/security workspace (@fuzefront/security-client@0.1.0) was added to the root package.json workspaces array but npm install was never run, so package-lock.json was missing these entries:

@fuzefront/security-client@0.1.0
@types/node@18.19.0
openapi-typescript@7.13.0
typescript@5.1.6

npm ci exits with EUSAGE when the lock file is out of sync, which caused Build & start backend to fail before the backend could start — killing all downstream Playwright steps.

Fix

Ran npm install at the repo root to regenerate package-lock.json (61 lines changed), committed only that file, and pushed to the fix branch above.

The fix branch cannot be auto-merged into this PR via Actions (repo policy blocks bot-created PRs), but the commit can be cherry-picked or the fix branch merged manually.

@github-actions

Copy link
Copy Markdown
Contributor

CI fix pushed — branch claude-auto-fix-ci-claude/9dots-menu-icon-name-68pjzm-29425835550

Root cause: packages/security (@fuzefront/security-client) was added to the root npm workspaces in #243 but package-lock.json was never regenerated after that. The devDependencies declared in packages/security/package.jsontypescript@5.1.6, openapi-typescript@7.13.0, @types/node@18.19.0 — were absent from the lock file, causing every npm ci call to fail with:

Missing: @fuzefront/security-client@0.1.0 from lock file
Missing: @types/node@18.19.0 from lock file
Missing: openapi-typescript@7.13.0 from lock file
Missing: typescript@5.1.6 from lock file

This broke Lint & Test (20.x), Identity UI + Security (unit), and transitively Notify Team.

Fix: Ran npm install --package-lock-only at the repo root to regenerate the lock file. Committed as 42407be on branch claude-auto-fix-ci-claude/9dots-menu-icon-name-68pjzm-29425835550.

A PR from this branch targeting claude/9dots-menu-icon-name-68pjzm could not be created programmatically (Actions permissions). Please open the PR manually or merge the fix commit into the source branch.

@github-actions

Copy link
Copy Markdown
Contributor

CI Fix — gate-frontend-build failure

Root cause: @fuzefront/chat-client and @fuzefront/chat-ui were bumped from v1.0.0 → v1.1.0, but frontend/package-lock.json still referenced them at v1.0.0. The gate-frontend-build job's npm ci step detected the lock file/package version mismatch and exited with error code 1. The truncated CI log (g: typescript@5.1.6 from lock file) is the tail of npm's out-of-sync error message.

Fix: Regenerated frontend/package-lock.json with npm install --package-lock-only inside the frontend/ directory to align it with the actual package versions.

Branch with fix: claude-auto-fix-ci-claude/9dots-menu-icon-name-68pjzm-29425895080
Commit: 127d666

The fix is a single-file, 3-line change to frontend/package-lock.json. Please merge this branch into claude/9dots-menu-icon-name-68pjzm (the PR head branch) to unblock CI.

The packages/chat-client and packages/chat-ui workspaces were bumped to
1.1.0, but frontend/package-lock.json (the frontend is a standalone npm
project, not a root workspace) still pinned them at 1.0.0, so `npm ci` in
gate-frontend-build failed on the version mismatch. Regenerated the frontend
lock (npm install --package-lock-only); only the chat-client/chat-ui
versions change. `npm ci --dry-run` now exits 0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016PMVXVQ5XUh8ZfFx8Vr7XW
@github-actions

Copy link
Copy Markdown
Contributor

CI Fix — gate-frontend-build

Root cause: frontend/package-lock.json was missing nested node_modules/typescript entries for two workspace packages that pin TypeScript at exactly 5.1.6:

  • ../packages/chat-client (devDep: "typescript": "5.1.6")
  • ../packages/chat-ui (devDep: "typescript": "5.1.6")

The lock file had hoisted node_modules/typescript@5.9.3 (for the frontend's own ^5.7.3) but no entry for 5.1.6. npm ci on Node 20 validates all workspace devDependencies against the lockfile and fails with Missing: typescript@5.1.6 from lock file. The root package-lock.json already has the correct nested entries (packages/chat-client/node_modules/typescript@5.1.6); the frontend lock file was never updated to include equivalents.

Fix: Added two missing nested entries to frontend/package-lock.json:

  • ../packages/chat-client/node_modules/typescript@5.1.6
  • ../packages/chat-ui/node_modules/typescript@5.1.6

No source code or package.json files changed.

Branch: claude-auto-fix-ci-claude/9dots-menu-icon-name-68pjzm-29425745699
Commit: ca9007f

Note: Could not open a PR automatically (Actions token lacks pull-requests: write for PR creation). Please open the PR manually from that branch targeting claude/9dots-menu-icon-name-68pjzm.

@github-actions

Copy link
Copy Markdown
Contributor

CI Failure Root Cause & Fix

Root cause: Both PostgreSQL service containers in .github/workflows/backend-tests.yml use pg_isready as the health check without specifying a user:

--health-cmd pg_isready

Inside the postgres:15-alpine container, pg_isready runs as the OS root user. Since root is not a PostgreSQL role, the server logs FATAL: role "root" does not exist and the health check exits non-zero. After 5 consecutive failures (--health-retries 5), the service is marked unhealthy and GitHub Actions refuses to start any job steps — so no tests ever run, and all three jobs fail.

This is unrelated to the PR's frontend/design-system changes; the workflow file had a latent bug that became visible (e.g. due to Docker/runner environment drift).

Fix — two lines in .github/workflows/backend-tests.yml:

In the test job (line ~34) and the permit-integration job (line ~195), change:

--health-cmd pg_isready

to:

--health-cmd "pg_isready -U postgres"

This makes the health check authenticate as the postgres role (which exists), causing it to pass immediately and allowing all job steps to run.

Note: A fix commit was prepared but could not be pushed because the bot token lacks the workflows scope needed to update .github/workflows/ files. A human with workflows-scoped credentials can apply these two one-line changes directly.

@github-actions

Copy link
Copy Markdown
Contributor

CI fix — branch pushed

CI was failing on all three jobs (Backend tests Node 22.x/24.x, Permit.io integration tests) with the same root cause:

npm error Missing: @fuzefront/security-client@0.1.0 from lock file
npm error Missing: @types/node@18.19.0 from lock file
npm error Missing: openapi-typescript@7.13.0 from lock file
npm error Missing: typescript@5.1.6 from lock file

packages/security (@fuzefront/security-client@0.1.0) is listed in the root workspaces array in package.json, but the workspace entry was absent from package-lock.json. Every npm ci step failed before any tests ran, which is why jest: not found also appeared.

Root cause: PR #252 (1723cba) regenerated package-lock.json without the packages/security workspace entries. These are unrelated to this PR's changes (design-system / AppTile).

Fix: Ran npm install --package-lock-only to resync the lock file. No application code changed.

Fix is on branch claude-auto-fix-ci-claude/9dots-menu-icon-name-68pjzm-29425700768 (commit aa0a2b4). Once CI passes on that branch, it can be merged here.

@github-actions

Copy link
Copy Markdown
Contributor

CI Fix — Playwright sign-in flow

Branch pushed: claude-auto-fix-ci-claude/9dots-menu-icon-name-68pjzm-29426371148

Root Cause

Two combined issues caused the "Playwright sign-in flow" timeout in run #29425945512:

  1. Monolith missing /api/v1/security routes: After PR feat(authn): de-vendor auth frontend onto provider-neutral Security API #250 de-vendored the frontend onto the provider-neutral Security API, authAPI.login() calls POST /api/v1/security/session. But the CI only starts the monolith (backend/src/index.ts), which has no handler for that path — requests fell through to the 404 handler.

  2. Test predicate checking the old URL: frontend/tests/auth-simple.spec.ts:19 still waited for response.url().includes('/api/auth/login'), while the actual browser request goes to /v1/security/session. This caused the 15 s waitForResponse timeout.

Fix (3 files)

File Change
backend/src/routes/securityShim.ts New: bcrypt+JWT handler for POST /session, GET /session, GET /methods — same contract as the security-service but backed by the local DB (no Authentik needed in CI)
backend/src/index.ts Mount the shim at /api/v1/security; the dedicated security-service owns these in production
frontend/tests/auth-simple.spec.ts Change waitForResponse predicate from /api/auth/login/v1/security/session

The fix is on the branch above. PR creation is blocked for the bot (createPullRequest permission not granted), so a maintainer will need to open a PR from that branch targeting claude/9dots-menu-icon-name-68pjzm to unblock this.

@github-actions

Copy link
Copy Markdown
Contributor

CI Fix Investigation — Playwright sign-in flow

Root Cause:

The Playwright tests were failing with:

TimeoutError: page.waitForResponse: Timeout 15000ms exceeded

The frontend (frontend/src/services/api.ts) was updated to call POST /api/v1/security/session (the new Security API) for login. The E2E CI only starts the monolith (backend/), which only exposes POST /api/auth/login — NOT the new /api/v1/security/session path. The tests also still filtered waitForResponse on /api/auth/login (the old URL), so no match was ever found.

Fix applied on branch claude-auto-fix-ci-claude/9dots-menu-icon-name-68pjzm-29426758584:

  1. backend/src/routes/security-compat.ts — New compatibility router exposing GET /methods, POST /session, GET /session, DELETE /session under /api/v1/security using the monolith's local-DB auth. Mounted in backend/src/index.ts.

  2. frontend/tests/auth-simple.spec.ts + clock-load.spec.ts — Updated waitForResponse URL filters from /api/auth/login/api/v1/security/session.

Note: GitHub Actions does not permit this bot account to open PRs. The fix is committed and pushed to the fix branch; someone with PR-creation permissions can open the PR targeting claude/9dots-menu-icon-name-68pjzm.

@github-actions

Copy link
Copy Markdown
Contributor

CI Fix Applied — Branch Ready

The Playwright sign-in CI failure has been diagnosed and fixed. The fix has been pushed to branch claude-auto-fix-ci-claude/9dots-menu-icon-name-68pjzm-29430690945.

Root cause: The frontend was updated to POST to /api/v1/security/session (the new security-service API shape) for login, but the E2E CI environment only runs the monolith (backend/), which only had POST /api/auth/login. This resulted in a 404, and the Playwright test URL filters were still matching the old /api/auth/login endpoint — causing a 15s timeout.

Fix applied (cherry-picked from sibling auto-fix branch c81c58d):

  1. backend/src/routes/security-compat.ts — new compat shim that exposes GET /methods, POST /session, GET /session, and DELETE /session under /api/v1/security using the monolith's local-DB auth logic. Mounted in backend/src/index.ts before the legacy /api/auth routes.

  2. frontend/tests/auth-simple.spec.ts and frontend/tests/clock-load.spec.ts — updated waitForResponse URL filter from /api/auth/login/api/v1/security/session.

Note: Unable to open a PR automatically (GitHub Actions PR-create permission is restricted). The fix branch is pushed and ready for review/merge at claude-auto-fix-ci-claude/9dots-menu-icon-name-68pjzm-29430690945.

@izzywdev
izzywdev merged commit 43a03bc into master Jul 21, 2026
11 of 49 checks passed
@izzywdev
izzywdev deleted the claude/9dots-menu-icon-name-68pjzm branch July 21, 2026 04:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants